// Copyright (c) Appeon. All rights reserved.
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. 
// You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0.

using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Threading;
using System.Threading.Tasks;

namespace SnapObjects.Data
{
    /// <summary>
    ///     Provides a series of methods for manipulating data after loaded.
    /// </summary>
    /// <typeparam name="TModel">The type of a model class.</typeparam>
    public interface ILoadable<TModel>
    {
        //ILoadable<TModel> Load(params object[] parameters);

        //ILoadable<TModel> LoadAll();

        //ILoadable<TModel> LoadByKey(params object[] parameters);

        /// <summary>
        ///     Loads data for the specified embedded property in TModel for all rows.If the ModelEmbedded 
        ///     attribute is applied in the property, the property will use the SQL query(defined in the 
        ///     detail model class specified by the ModelType property of the ModelEmbedded attribute) to 
        ///     retrieve data from database.The cascade parameter can be used to decide whether to retrieve 
        ///     data for the embedded properties in the detail model or the granddetail model.
        /// </summary>
        /// <param name="property">
        ///     An embedded property of TModel class.
        ///     This property is specified by an expression.
        /// </param>
        /// <param name="cascade">
        /// Only when the ModelEmbedded attribute is applied in the property, the cascade parameter can be 
        /// used to decide whether to retrieve data for the embedded properties in the detail model or the 
        /// granddetail model. See master-detail-granddetail for more info.The default value is false.
        /// </param>
        /// <returns>
        ///     Returns the current <see cref="ILoadable{TModel}"/> object whose methods can be used to further obtain 
        ///     the data result set or perform data operations such as embedded queries.
        /// </returns>
        ILoadable<TModel> Include(Expression<Func<TModel, object>> property, bool cascade = false);

        /// <summary>
        ///     Asynchronously loads data for the specified embedded property in TModel for all rows.If the ModelEmbedded 
        ///     attribute is applied in the property, the property will use the SQL query(defined in the 
        ///     detail model class specified by the ModelType property of the ModelEmbedded attribute) to 
        ///     retrieve data from database.The cascade parameter can be used to decide whether to retrieve 
        ///     data for the embedded properties in the detail model or the granddetail model.
        /// </summary>
        /// <param name="property">
        ///     An embedded property of TModel class.
        ///     This property is specified by an expression.
        /// </param>
        /// <param name="cascade">
        ///     Only when the ModelEmbedded attribute is applied in the property, the cascade parameter can be 
        ///     used to decide whether to retrieve data for the embedded properties in the detail model or the 
        ///     granddetail model. See master-detail-granddetail for more info.The default value is false.
        /// </param>
        /// <param name="cancellationToken">
        ///     (Optional) A cancellation token that can be used by other objects or threads to receive notice of cancellation.
        /// </param>
        /// <returns>
        ///     Returns a task that represents the asynchronous operation.
        /// </returns>
        Task<ILoadable<TModel>> IncludeAsync(
            Expression<Func<TModel, object>> property, 
            bool cascade = false, 
            CancellationToken cancellationToken = default);

        /// <summary>
        ///     Loads data for the specified embedded property in TModel for the specified row. If the ModelEmbedded 
        ///     attribute is applied in the property, the property will use the SQL query(defined in the detail model 
        ///     class specified by the ModelType property of the ModelEmbedded attribute) to retrieve data from database.
        ///     The cascade parameter can be used to decide whether to retrieve data for the embedded properties in the 
        ///     detail model or the granddetail model.
        /// </summary>
        /// <param name="index">The zero-based index for the row in the result set.</param>
        /// <param name="property">
        ///     An embedded property of TModel class.
        ///     This property is specified by an expression.
        /// </param>
        /// <param name="cascade">
        ///     Only when the ModelEmbedded attribute is applied in the property, the cascade parameter can be used 
        ///     to decide whether to retrieve data for the embedded properties in the detail model or granddetail model. 
        ///     See master-detail-granddetail for more info.The default value is false.
        /// </param>
        /// <returns>
        ///     Returns the current <see cref="ILoadable{TModel}"/> object whose methods can be used to further obtain the data result 
        ///     set or perform data operations such as embedded queries.
        /// </returns>
        ILoadable<TModel> Include(int index, Expression<Func<TModel, object>> property, bool cascade = false);

        /// <summary>
        ///     Asynchronously loads data for the specified embedded property in TModel for the specified row. If the ModelEmbedded 
        ///     attribute is applied in the property, the property will use the SQL query(defined in the detail model 
        ///     class specified by the ModelType property of the ModelEmbedded attribute) to retrieve data from database.
        ///     The cascade parameter can be used to decide whether to retrieve data for the embedded properties in the 
        ///     detail model or the granddetail model.
        /// </summary>
        /// <param name="index">The zero-based index for the row in the result set.</param>
        /// <param name="property">
        ///     An embedded property of TModel class.
        ///     This property is specified by an expression.
        /// </param>
        /// <param name="cascade">
        ///     Only when the ModelEmbedded attribute is applied in the property, the cascade parameter can be used 
        ///     to decide whether to retrieve data for the embedded properties in the detail model or granddetail model. 
        ///     See master-detail-granddetail for more info.The default value is false.
        /// </param>
        /// <param name="cancellationToken">
        ///     (Optional) A cancellation token that can be used by other objects or threads to receive notice of cancellation.
        /// </param>
        /// <returns>
        ///    Returns a task that represents the asynchronous operation.
        /// </returns>
        Task<ILoadable<TModel>> IncludeAsync(
            int index, Expression<Func<TModel, object>> property, 
            bool cascade = false, 
            CancellationToken cancellationToken = default);

        /// <summary>
        ///     Loads data for the embedded properties in TModel for all rows. If the ModelEmbedded attribute is applied 
        ///     in the property, the property will use the SQL query(defined in the detail model class specified by the 
        ///     ModelType property of the ModelEmbedded attribute) to retrieve data from database.The cascade parameter 
        ///     can be used to decide whether to retrieve data for the embedded properties in the detail model or the 
        ///     granddetail model.
        /// </summary>
        /// <param name="cascade">
        ///     Only when the ModelEmbedded attribute is applied in the property, the cascade parameter can be used to 
        ///     decide whether to retrieve data for the embedded properties in the detail model or the granddetail model. 
        ///     See master-detail-granddetail for more info. The default value is false.
        /// </param>
        /// <returns>
        ///     Returns the current <see cref="ILoadable{TModel}"/> object whose methods can be used to further obtain the data result 
        ///     set or perform data operations such as embedded queries.
        /// </returns>
        ILoadable<TModel> IncludeAll(bool cascade = false);

        /// <summary>
        ///     Asynchronously loads data for the embedded properties in TModel for all rows. If the ModelEmbedded attribute is applied 
        ///     in the property, the property will use the SQL query(defined in the detail model class specified by the 
        ///     ModelType property of the ModelEmbedded attribute) to retrieve data from database.The cascade parameter 
        ///     can be used to decide whether to retrieve data for the embedded properties in the detail model or the 
        ///     granddetail model.
        /// </summary>
        /// <param name="cascade">
        ///     Only when the ModelEmbedded attribute is applied in the property, the cascade parameter can be used to 
        ///     decide whether to retrieve data for the embedded properties in the detail model or the granddetail model. 
        ///     See master-detail-granddetail for more info. The default value is false.
        /// </param>
        /// <param name="cancellationToken">
        ///     (Optional) A cancellation token that can be used by other objects or threads to receive notice of cancellation.
        /// </param>
        /// <returns>
        ///     Returns a task that represents the asynchronous operation.
        /// </returns>
        Task<ILoadable<TModel>> IncludeAllAsync(
            bool cascade = false, CancellationToken cancellationToken = default);

        /// <summary>
        ///     Loads data for the embedded properties (where the ModelEmbedded attribute or the SqlEmbedded attribute is applied) 
        ///     in TModel for the specified row. If the ModelEmbedded attribute is applied in the property, the property will use 
        ///     the SQL query(defined in the detail model class specified by the ModelType property of the ModelEmbedded attribute) 
        ///     to retrieve data from database.The cascade parameter can be used to decide whether to retrieve data for the embedded 
        ///     properties in the detail model or the granddetail mode.
        /// </summary>
        /// <param name="index">The zero-based index for the row in the result set.</param>
        /// <param name="cascade">
        ///     Only when the ModelEmbedded attribute is applied in the property, the cascade parameter can be used to decide 
        ///     whether to retrieve data for embedded properties in the detail model or granddetail model. See master-detail-granddetail 
        ///     for more info. The default value is false.
        /// </param>
        /// <returns>
        ///     Returns the current <see cref="ILoadable{TModel}"/> object whose methods can be used to further obtain the data result set or 
        ///     perform data operations such as embedded queries.
        /// </returns>
        ILoadable<TModel> IncludeAll(int index, bool cascade = false);

        /// <summary>
        ///     Asynchronously loads data for the embedded properties (where the ModelEmbedded attribute or the SqlEmbedded attribute is applied) 
        ///     in TModel for the specified row. If the ModelEmbedded attribute is applied in the property, the property will use 
        ///     the SQL query(defined in the detail model class specified by the ModelType property of the ModelEmbedded attribute) 
        ///     to retrieve data from database.The cascade parameter can be used to decide whether to retrieve data for the embedded 
        ///     properties in the detail model or the granddetail mode.
        /// </summary>
        /// <param name="index">The zero-based index for the row in the result set.</param>
        /// <param name="cascade">
        ///     Only when the ModelEmbedded attribute is applied in the property, the cascade parameter can be used to decide 
        ///     whether to retrieve data for embedded properties in the detail model or granddetail model. See master-detail-granddetail 
        ///     for more info. The default value is false.
        /// </param>
        /// <param name="cancellationToken">
        ///     (Optional) A cancellation token that can be used by other objects or threads to receive notice of cancellation.
        /// </param>
        /// <returns>
        ///     Returns a task that represents the asynchronous operation.
        /// </returns>
        Task<ILoadable<TModel>> IncludeAllAsync(
            int index, bool cascade = false, CancellationToken cancellationToken = default);

        /// <summary>
        ///     Returns the first data record in the result set. If there is no data in the result set, 
        ///     returns the default value.
        /// </summary>
        /// <returns>
        ///     Returns a TModel object which represents the first row of the result set loaded, 
        ///     or returns null if no rows loaded.
        /// </returns>
        TModel FirstOrDefault();

        /// <summary>
        ///     Creates a <see cref="List{TModel}"/> object from the result set.
        /// </summary>
        /// <returns>Returns a <see cref="List{TModel}"/> object that includes all of the data of the result set.</returns>
        List<TModel> ToList();

        /// <summary>
        ///     Converts the result set to an array.
        /// </summary>
        /// <returns>An array that contains all of the data of the result set.</returns>
        TModel[] ToArray();

        /// <summary>
        ///     Creates a <see cref="Dictionary{Tkey, TModel}"/> object from the result set according to the specified key selector function.
        /// </summary>
        /// <typeparam name="TKey"></typeparam>
        /// <param name="keySelector">A function used to specify the key of the dictionary.</param>
        /// <returns>Returns a <see cref="Dictionary{Tkey, TModel}"/> object that includes all of the data of the result set.</returns>
        Dictionary<TKey, TModel> ToDictionary<TKey>(Func<TModel, TKey> keySelector);
    }
}
